import sys
sys.path.append("/var/lib/zope/Extensions")
import random
import poset

def random_request(Poset):
	Requests = []
	num_request = [1,2]
	Requests.append( [[]] )		
	for x in range(random.choice(num_request)):
		element = dict()
		element2 = []
		keys = Poset.keys()
		keys.sort()	
		for attribute_name in keys:
			attr_values = Poset[attribute_name]	
			val = random.choice(attr_values)
			element[attribute_name] = val
			element2.append(val)
		Requests[0][0].append(element)
	return Requests	



def request_to_str_single(Poset,req,Resources):
	request = req[0]
	entry_point = None
	try: entry_point = req[1]
	except: pass
	keys = Poset.keys()
	keys.sort()	
	r_str =""
	if entry_point is not None:
		reso =  Resources[entry_point]
		r_str = ",".join( [str(reso[key]) for  	key in keys] )
	#r_str =  poset.resource_to_str(Poset,reso)
	return "<".join([  ",".join( [str(elem[k]) for k in keys]) for elem in request ])+" "+r_str 

def requests_to_str(Poset,Requests,Resources):
	return "\n".join([request_to_str_single(Poset,request,Resources)  for request in Requests])

def parse_values(Poset,range_part,check = None):
	if check is None: check = True
	keys =  Poset.keys()
	keys.sort()	
	expected_len = len(keys)	
	values = [x.strip() for x in range_part.split(",")]
	if len(values) != expected_len:	return False,""
	else:
		values_ok = []
		myvalues = dict()
		if check:
			for vali in range(len(values)):
				found = False
				val = str(values[vali].strip())
				if len(val) == 0:
					values_ok.append(None)
					myvalues[keys[vali]] = None
				else: 
					for x in Poset[keys[vali]]:
						if str(x) == val:
							found = True
							values_ok.append(x)
							myvalues[keys[vali]] = x
							break
					if not found:
						return False," -> value not found:"+str(val)+" explain: "+str(values)+";"+str(keys)+";"+str(range_part)
		else:
			for vali in range(len(values)):
				x = Poset[keys[vali]][0]
				val = str(values[vali].strip())
				if type(x) == type( "" ):
					values_ok.append(val)
					myvalues[keys[vali]] = val  
				else:	
					mytype = type(x)
					values_ok.append ( mytype(val) )
					myvalues[keys[vali]] =  mytype(val) 
		if len(values_ok) == expected_len: return True,myvalues
		else: return False," not  enough values "


def parse_line_request(Poset,line2):
	while line2.find("  ") > -1: line2 = line2.replace("  "," ")
	line2 = line2.strip()
	if len(line2) == 0 : return None
	request = line2.split(" ")
	if len(request) not in 	(1,2):
		raise Exception("bad number of part separated by space into the query")
	range = request[0].split("<")
	if len(range)  not in (1,2):
		raise Exception("bad number of resource in query: should be 1 (point query) or 2 (for range query)")
	range_request = []
	for range_part in range:	
		ret_code, values_of_request = parse_values(Poset,range_part,False)
		if not ret_code:
			raise Exception("error while parsing values of point \""+str(range_part)+"\" in request: "+str(values_of_request))
			
		else: range_request.append(values_of_request)
	#-------------------------
	if len(request) > 1:
		ret_code, value_of_entry_point_value_for_the_request = parse_values(Poset,request[1],True)
		if not ret_code:
			raise Exception("error while parsing values of 2nd point in request: "+str(value_of_entry_point_value_for_the_request)+" => "+str(request[1]))
		for k,v in value_of_entry_point_value_for_the_request.items():
			if v is None:
				raise Exception("missing a value for entry-point specification \""+str(request[1])+"\": "+str(value_of_entry_point_value_for_the_request)) 
		return [range_request, value_of_entry_point_value_for_the_request]	
	else:
		return [ range_request ]	


def read_requests(Poset,file_path):
	""" read a poset description from a file"""
	f = file(file_path,"r")
	Requests = []
	try:
		line =f.readline()
		lineno = 0
		while len(line) > 0:
			lineno += 1
			line2 = line[:-1]
			try:
				req_and_entry_point = parse_line_request(Poset,line2)
				if req_and_entry_point is not None: 	
					Requests.append( req_and_entry_point  )	
			except Exception,e: 
				raise Exception("while reading request at line "+str(lineno)+" \""+str(line2)+"\" \n"+str(e))
			line =f.readline()
	finally: f.close()
	return Requests 

def build_requests(Poset,data):
	Requests = []
	lineno = 0
	for line in data.split("\n"):
		lineno += 1
		line2 = line
		try:
			req_and_entry_point = parse_line_request(Poset,line2)
			if req_and_entry_point is not None: 	
				Requests.append( req_and_entry_point  )	
		except Exception,e: 
			from traceback import print_exc
			print_exc()
			raise Exception("while reading request at line "+str(lineno)+" \""+str(line2)+"\" \n"+str(e))
	return Requests 

def build_entry_points(Poset,Graph,Resources,requests):
	nodes = Graph.nodes()
	messages = [] 
	for request_i in range(len(requests)):
		request  = requests[request_i]	
		if len(request) == 1:
			messages.append("generate random entry_point for request no"+str(request_i)+":"+str(request[0]))
			requests[request_i].append(random.choice( nodes ) )
		else:
			entry_point = None
			entry_point_val = request[1]
			for node in nodes:
				if Resources[node] == entry_point_val:
					entry_point = node
			if entry_point is None:
				raise Exception("entry_point node not found with values: "+str(entry_point_val))
			else:
				requests[request_i][-1] = entry_point 		
	return requests




def build(Poset,Graph,Resources,options):
	""" build the request objects"""
	if not options.has_key("request"):
		if options["verbose"]:
			print >>sys.stderr,"request not specified, generating random ones"
		requests =  random_request(Poset)
	else:
		requests =  read_requests(Poset,options["request"])
	nodes = Graph.nodes()
	for request_i in range(len(requests)):
		request  = requests[request_i]	
		if len(request) == 1:
			if options["verbose"]:
				print "generate random allocator for request no"+str(request_i)+":",request[0]
			requests[request_i].append(random.choice( nodes ) )
		else:
			allocator = None
			allocator_val = request[1]
			for node in nodes:
				if Resources[node] == allocator_val:
					allocator = node
					if options["verbose"]:
						print "found allocator, node",allocator,"for request no"+str(request_i)+":",request[0]
					break
			if allocator is None:
				raise Exception("allocator node not found with values: "+str(allocator_val))
			else:
				requests[request_i][-1] = allocator 		
	return requests

